import { nextTick } from "../utils/index.js";
import { popTarget, pushTarget } from "./dep";
// 每个 watcher 对应不同的id
let id = 0;

class Watcher {
    constructor(vm, expOrFn, cb, options) {
        // vue实例
        this.vm = vm
        // 传过来的变量或函数（自定义的watch传过来是变量）
        this.expOrFn = expOrFn
        // 回调函数
        this.cb = cb
        // 参数
        this.options = options
        // 唯一标识
        this.id = id++
        // 当前是否是用户自定义的 watcher
        this.isUser = options.user
        // 当前 watcher 所对应的依赖
        this.deps = []
        this.depId = new Set()
        // 是否是 计算属性
        this.lazy = options.lazy
        this.dirty = this.lazy

        if (typeof this.expOrFn == 'function') {
            this.getter = expOrFn
        } else { // a.a.a 这种字符串
            this.getter = function () {
                let paths = expOrFn.split('.')
                let path
                let res = vm
                while (path = paths.shift()) {
                    res = res[path]
                }
                return res
            }
        }
        // 创建 watcher 就更新页面
        this.value = this.lazy ? void 0 : this.get();
    }

    get() {
        // 利用 js 单线程的原理，先往 Dep 中添加 watcher，随即更新页面
        pushTarget(this)
        // 更新 页面
        const res = this.getter.call(this.vm)
        // 去除 当前 watcher
        popTarget()
        return res
    }
    // 更新页面
    run() {
        // 更新 watch 的新旧值
        const newVal = this.get()
        const oldVal = this.value
        this.value = newVal
        if (this.isUser) {
            this.cb.call(this.vm, newVal, oldVal)
        }
        this.get()
    }
    // 异步处理所有的 watcher
    update() {
        if (this.lazy) {
            this.dirty = true
        } else {
            queueWatcher(this)
        }

    }

    // 一个 watcher 对应 几个dep
    addDep(dep) {
        let id = dep.id
        if (!this.depId.has(id)) {
            this.deps.push(dep);
            this.depId.add(id)
            // 为 dep 添加 当前的 依赖 watcher
            dep.addSub(this)
        }
    }
    // 计算属性 计算数据
    evaluate() {
        this.value = this.get()
        this.dirty = false
    }

    // 计算属性 更新其他 watcher
    depend() {
        let i = this.deps.length
        while (i--) {
            this.deps[i].depend()
        }
    }

}

// 异步处理 watcher
let queue = []
let pending = false
let has = {}

function flashQueue() {
    queue.forEach(watcher => {
        watcher.run()
        if (!watcher.isUser) {
            watcher.cb()
        }

    })
    queue = []
    has = {}
    pending = false
}

// 防抖原理
function queueWatcher(watcher) {
    const id = watcher.id;
    // 判断是否重复执行
    if (has[id] == null) {
        queue.push(watcher)
        has[id] = id;
        if (!pending) {
            setTimeout(() => {
                // nextTick原理
                nextTick(flashQueue)
            }, 0)
            pending = true
        }

    }
}



export default Watcher